module dgl.Vector3;

import str = tango.text.convert.Float;

import tango.math.Math;
import dgl.Matrix;
import dgl.Vector2;

struct Vector3
{
	private float[3] m_vector;

	public float x()
	{
		return m_vector[0];
	}

	public float y()
	{
		return m_vector[1];
	}

	public float z()
	{
		return m_vector[2];
	}

	public void x( float x )
	{
		m_vector[0] = x;
	}

	public void y( float y )
	{
		m_vector[1] = y;
	}

	public void z( float z )
	{
		m_vector[2] = z;
	}

	public float * ptr()
	{
		return m_vector.ptr;
	}
	
	public float length()
	{
		return sqrt( x * x + y * y + z * z );
	}

	public static Vector3 opCall( float x, float y, float z )
	{
		Vector3 ret;
		ret.x = x;
		ret.y = y;
		ret.z = z;
		return ret;
	}

	public static Vector3 opCall( float value )
	{
		Vector3 ret;
		ret.x = value;
		ret.y = value;
		ret.z = value;
		return ret;
	}

	public static Vector3 opCall( Vector2 value, float z )
	{
		Vector3 ret;
		ret.x = value.x;
		ret.y = value.y;
		ret.z = z;
		return ret;
	}

	public static Vector3 zero()
	{
		return Vector3( 0, 0, 0 );
	}
	
	public static Vector3 one()
	{
		return Vector3( 1, 1, 1 );
	}
	
	public static Vector3 unitX()
	{
		return Vector3( 1, 0, 0 );
	}
	
	public static Vector3 unitY()
	{
		return Vector3( 0, 1, 0 );
	}
	
	public static Vector3 unitZ()
	{
		return Vector3( 0, 0, 1 );
	}

	public static Vector3 cross( Vector3 vector1, Vector3 vector2 )
	{
		Vector3 vector;
		vector.x = ( vector1.y * vector2.z ) - ( vector1.z * vector2.y );
		vector.y = ( vector1.z * vector2.x ) - ( vector1.x * vector2.z );
		vector.z = ( vector1.x * vector2.y ) - ( vector1.y * vector2.x );
		return vector;
	}
	
	public static Vector3 clamp( Vector3 value1, Vector3 min, Vector3 max )
	{
		Vector3 vector;
		float x = value1.x;
		x = ( x > max.x ) ? max.x : x;
		x = ( x < min.x ) ? min.x : x;
		float y = value1.y;
		y = ( y > max.y ) ? max.y : y;
		y = ( y < min.y ) ? min.y : y;
		float z = value1.z;
		z = ( z > max.z ) ? max.z : z;
		z = ( z < min.z ) ? min.z : z;
		vector.x = x;
		vector.y = y;
		vector.z = z;
		return vector;
	}

	public static Vector3 normalize( Vector3 value )
	{
		Vector3 vector;
		float num2 = ( ( value.x * value.x ) + ( value.y * value.y ) ) + ( value.z * value.z );
		float num = 1f / sqrt( num2 );
		vector.x = value.x * num;
		vector.y = value.y * num;
		vector.z = value.z * num;
		return vector;
	}

	public static float dot( Vector3 vector1, Vector3 vector2 )
	{
		return ( ( ( vector1.x * vector2.x ) + ( vector1.y * vector2.y ) ) + ( vector1.z * vector2.z ) );
	}
	
	public static float distance( Vector3 value1, Vector3 value2 )
	{
		float num3 = value1.x - value2.x;
		float num2 = value1.y - value2.y;
		float num = value1.z - value2.z;
		float num4 = ( ( num3 * num3 ) + ( num2 * num2 ) ) + ( num * num );
		return ( sqrt( num4 ) );
	}
	
	public static float distanceSquared( Vector3 value1, Vector3 value2 )
	{
		float num3 = value1.x - value2.x;
		float num2 = value1.y - value2.y;
		float num = value1.z - value2.z;
		return ( ( ( num3 * num3 ) + ( num2 * num2 ) ) + ( num * num ) );
	}
	
	public static Vector3 transform( Vector3 position, Matrix matrix )
	{
		Vector3 vector;
		float num3 = ( ( ( position.x * matrix.m11 ) + ( position.y * matrix.m21 ) ) + ( position.z * matrix.m31 ) ) + matrix.m41;
		float num2 = ( ( ( position.x * matrix.m12 ) + ( position.y * matrix.m22 ) ) + ( position.z * matrix.m32 ) ) + matrix.m42;
		float num = ( ( ( position.x * matrix.m13 ) + ( position.y * matrix.m23 ) ) + ( position.z * matrix.m33 ) ) + matrix.m43;
		vector.x = num3;
		vector.y = num2;
		vector.z = num;
		return vector;
	}

	public Vector3 opAdd( Vector3 value )
	{
		Vector3 vector;
		vector.x = this.x + value.x;
		vector.y = this.y + value.y;
		vector.z = this.z + value.z;
		return vector;
	}

	public Vector3 opSub( Vector3 value )
	{
		Vector3 vector;
		vector.x = this.x - value.x;
		vector.y = this.y - value.y;
		vector.z = this.z - value.z;
		return vector;
	}
	
	public Vector3 opMul( float value )
	{
		Vector3 vector;
		vector.x = this.x * value;
		vector.y = this.y * value;
		vector.z = this.z * value;
		return vector;
	}
	
	public Vector3 opDiv( float value )
	{
		Vector3 vector;
		vector.x = this.x / value;
		vector.y = this.y / value;
		vector.z = this.z / value;
		return vector;
	}

	public char[] toString()
	{
		char[] ret = "";
		ret ~= "{ " ~ str.toString( x );
		ret ~= ", " ~ str.toString( y );
		ret ~= ", " ~ str.toString( z );
		ret ~= " }";
		return ret;
	}
}